package cn.superchart.module.dev.gencode.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.superchart.common.utils.Checker;
import cn.superchart.module.dev.gencode.param.GenCodeModel;
import cn.superchart.module.dev.gencode.param.ScGenTableDetailParam;
import cn.superchart.module.dev.genconfig.param.ScGenTableConfDetailParam;
import cn.superchart.module.dev.genconfig.param.ScTableConfQueryParam;
import cn.superchart.module.dev.genconfig.service.ScGenTableConfService;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.ds.ItemDataSource;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Slf4j
@Service
public class GenBuildToCodeService {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private ScGenTableConfService scGenTableConfService;

    private String[] initModules(String projectPath, ScGenTableDetailParam scGenTableDetailParam){
        String[] path = new String[3];
        Path basePath = Paths.get(projectPath ,"superchart-modules", scGenTableDetailParam.getPluginName());
        String absolutePath = basePath.toAbsolutePath().toString();
        if(!FileUtil.exist(absolutePath)){
            FileUtil.mkdir(absolutePath);
        }
        path[0] = absolutePath;
        Path baseApiPath = Paths.get(projectPath ,"superchart-modules-api", scGenTableDetailParam.getPluginName()+"-api");
        String absoluteApiPath = baseApiPath.toAbsolutePath().toString();
        if(!FileUtil.exist(absoluteApiPath)){
            FileUtil.mkdir(absoluteApiPath);
        }
        path[1] = absoluteApiPath;
        Path baseVuePath = Paths.get(projectPath ,"superchart-dashboard");
        path[2] = baseVuePath.toString();
        return path;
    }



    public void build(ScGenTableDetailParam scGenTableDetailParam ){
        if(Checker.BeNotNull(scGenTableDetailParam)){
            DynamicRoutingDataSource dataSources = (DynamicRoutingDataSource) dataSource;
            ItemDataSource itemDataSource = (ItemDataSource) dataSources.getDataSource("master");
            DruidDataSource druidDataSource = (DruidDataSource) itemDataSource.getRealDataSource();
            String projectPath = System.getProperty("user.dir");
            String[] outputDir = initModules(projectPath,scGenTableDetailParam);
            ScTableConfQueryParam scTableConfQueryParam = new ScTableConfQueryParam();
            scTableConfQueryParam.setBaseId(scGenTableDetailParam.getId());
            scTableConfQueryParam.setTableSchema(extractDatabaseName(druidDataSource.getUrl()));
            List<ScGenTableConfDetailParam> tableConfDetailParamList = scGenTableConfService.fieldQuery(scTableConfQueryParam);
            GenCodeModel genCodeModel = new GenCodeModel();
            genCodeModel.setTableDetail(scGenTableDetailParam);
            genCodeModel.setTableConfDetailParamList(tableConfDetailParamList);
            genCodeModel.setOutputDir(outputDir[0]);
            genCodeModel.setOutputApiDir(outputDir[1]);
            genCodeModel.setOutputVueDir(outputDir[2]);
            genCode(druidDataSource,genCodeModel);
        }
    }


    private void genCode(DruidDataSource druidDataSource, GenCodeModel genCodeModel){
        ScGenTableDetailParam tableDetail = genCodeModel.getTableDetail();
        List<ScGenTableConfDetailParam> tableConfDetailParamList = genCodeModel.getTableConfDetailParamList();
        String url = druidDataSource.getUrl();
        String userName = druidDataSource.getUsername();
        String password = druidDataSource.getPassword();
        String className = StringUtils.capitalize(tableDetail.getClassName());
        String lowerEntity = StringUtils.uncapitalize(className);
        // 使用 FastAutoGenerator 快速配置代码生成器
        FreemarkerTemplateEngine freemarkerTemplateEngine = new FreemarkerTemplateEngine();
        FastAutoGenerator generator = FastAutoGenerator.create(url, userName, password)
                .globalConfig(builder -> {
                    builder.author(tableDetail.getAuthor()) // 设置作者
                            .outputDir(genCodeModel.getOutputDir()); // 输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("/src/main/java/"+tableDetail.getPackageName()) // 设置父包名
                            .entity("entity") // 设置实体类包名
                            .mapper("mapper") // 设置 Mapper 接口包名
                            .service("service") // 设置 Service 接口包名
                            .serviceImpl("service.impl") // 设置 Service 实现类包名
                            .xml("mapper.mapping").moduleName(tableDetail.getModuleName()); // 设置 Mapper XML 文件包名
                })
                .strategyConfig(builder -> {
                    builder.addInclude(tableDetail.getTbTableName()) // 设置需要生成的表名
                            .entityBuilder().formatFileName(className)
                            .javaTemplate("/templates/entity.java")// 设置 java 实体 模板
                            .enableLombok() // 启用 Lombok
                            .enableTableFieldAnnotation() // 启用字段注解
                            .controllerBuilder()
                            .enableRestStyle().template("/templates/controller.java").formatFileName(className+"Controller")
                            .serviceBuilder().convertServiceFileName(entityName -> className+"Service")
                            .serviceTemplate("/templates/service.java")
                            .serviceImplTemplate("/templates/serviceImpl.java").convertServiceImplFileName(entityName -> className+"ServiceImpl")
                            .mapperBuilder().mapperXmlTemplate("/templates/mapper.xml").formatMapperFileName(className+"Mapper").formatXmlFileName(className+"Mapper");
                }).injectionConfig(build->{
                    Map<String, Object> columnConf = tableConfDetailParamList.stream().collect(Collectors.toMap(ScGenTableConfDetailParam::getFieldName, (p) -> p));
                    // 遍历原 Map 的键值对
                    LinkedHashMap<String, Object> newMap = new LinkedHashMap<>();
                    for (Map.Entry<String, Object> entry : columnConf.entrySet()) {
                        newMap.put(StrUtil.toCamelCase(entry.getKey().toLowerCase()),entry.getValue());
                    }
                    tableConfDetailParamList.forEach(columnDetail->columnDetail.setFieldName(StrUtil.toCamelCase(columnDetail.getFieldName().toLowerCase())));
                    columnConf.clear();
                    build.customMap(Collections.singletonMap("className", className))
                            .customMap(Collections.singletonMap("lowEntity", lowerEntity))
                            .customMap(Collections.singletonMap("columns",newMap))
                            .beforeOutputFile((tableInfo, objectMap) -> {
                                objectMap.put("lowEntity", lowerEntity);
                                objectMap.put("columns", newMap);
                                objectMap.put("columnRows", tableConfDetailParamList);
                                objectMap.put("functionName", tableDetail.getFunctionName());
                                objectMap.put("busName", tableDetail.getBusName().toLowerCase());
                                objectMap.put("pluginName", genCodeModel.getTableDetail().getPluginName());
                                Object packInfo = objectMap.get("package");
                                Map<String,Object> myPack = new HashMap();
                                BeanUtil.copyProperties(packInfo,myPack);
                                for(String key:myPack.keySet()){
                                    myPack.put(key,myPack.get(key).toString().replace("/src/main/java/",""));
                                }
                                objectMap.put("packInfo",myPack);
                                log.info("准备生成文件: " + tableInfo.getEntityName());
                                log.info(JSONUtil.toJsonStr(objectMap));
                                // 可以在这里添加自定义逻辑，如修改 objectMap 中的配置
                            })
                            .customFile(cusFile->{
                                cusFile.packageName("param").fileName("AddParam.java").templatePath("/templates/add.java.ftl").build();
                            })
                            .customFile(cusFile->{
                                cusFile.packageName("param").fileName("EditParam.java").templatePath("/templates/edit.java.ftl").build();
                            }).customFile(cusFile->{
                                cusFile.packageName("param").fileName("DetailParam.java").templatePath("/templates/detail.java.ftl").build();
                            }).customFile(cusFile->{
                                cusFile.packageName("param").fileName("PageParam.java").templatePath("/templates/page.java.ftl").build();
                            }).customFile(cusFile->{
                                cusFile.packageName("param").fileName("IdParam.java").templatePath("/templates/id.java.ftl").build();
                            });
                    Path pomFile = Paths.get(genCodeModel.getOutputDir() ,"pom.xml");
                    Path pomApiFile = Paths.get(genCodeModel.getOutputApiDir() ,"pom.xml");
                    if(!FileUtil.exist(pomFile.toAbsolutePath().toString())){
                        build.customFile(cusFile->{
                            cusFile.filePath(genCodeModel.getOutputDir()).fileName("pom.xml").formatNameFunction(t-> "").templatePath("/templates/pom.ftl").build();
                        });
                    }
                    if(!FileUtil.exist(pomApiFile.toAbsolutePath().toString())){
                        build.customFile(cusFile->{
                            cusFile.filePath(genCodeModel.getOutputApiDir()).fileName("pom.xml").formatNameFunction(t-> "").templatePath("/templates/pomApi.ftl").build();
                        });
                    }
                    build.customFile(cusFile->{
                        String pack = "/src/main/java/"+tableDetail.getPackageName()+"."+tableDetail.getModuleName()+".api";
                        cusFile.filePath(genCodeModel.getOutputApiDir()).packageName(pack).fileName("App.java").formatNameFunction(t-> "").templatePath("/templates/app.java.ftl").build();
                    });
                    // TODO 生成 vue 文件
                    build.customFile(cusFile->{
                        Path viewPath = Paths.get(genCodeModel.getOutputVueDir() ,"src", "views");
                        cusFile.filePath(viewPath.toString()).packageName(genCodeModel.getTableDetail().getBusName()).fileName("index.vue").formatNameFunction(t-> "").templatePath("/templates/index.vue.ftl").build();
                    });
                    build.customFile(cusFile->{
                        Path viewPath = Paths.get(genCodeModel.getOutputVueDir() ,"src", "views");
                        cusFile.filePath(viewPath.toString()).packageName(genCodeModel.getTableDetail().getBusName()).fileName("form.vue").formatNameFunction(t-> "").templatePath("/templates/form.vue.ftl").build();
                    });
                    build.customFile(cusFile->{
                        Path viewPath = Paths.get(genCodeModel.getOutputVueDir() ,"src");
                        cusFile.filePath(viewPath.toString()).packageName("api").fileName(genCodeModel.getTableDetail().getBusName()+".ts").formatNameFunction(t-> "").templatePath("/templates/index.ts.ftl").build();
                    });

                    build.build();
                })
                .templateEngine(freemarkerTemplateEngine); // 使用 Freemarker 模板引擎
                generator.execute();
    }


    public static String extractDatabaseName(String jdbcUrl) {
        if (jdbcUrl == null || jdbcUrl.isEmpty()) {
            throw new IllegalArgumentException("JDBC URL 不能为空");
        }
        // 正则表达式解析数据库名称
        String regex = "jdbc:mysql://[^/]+/([^?]+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(jdbcUrl);
        if (matcher.find()) {
            return matcher.group(1); // 获取匹配的数据库名称
        } else {
            System.err.println("无法从 URL 中提取数据库名称: " + jdbcUrl);
            return null;
        }
    }
}
